package com.ptswitch.material.model.contract;

import java.math.BigDecimal;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.validation.constraints.Size;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.tapestry5.beaneditor.DataType;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.validator.constraints.NotBlank;
import org.hxzon.project.BaseEntity;
import org.hxzon.tapestry5.util.TapestryEx;
import org.hxzon.util.BigDecimalUtil;

import com.ptswitch.material.model.common.Uzer;

@Entity
public class Contract extends BaseEntity {
    public static final String Status_UnOk = "未完成";
    public static final String Status_Ok = "已完成";
    public static final String Status_Cancel = "已取消";

    private static final long serialVersionUID = 6705569910023553421L;

    @OneToMany(mappedBy = "contract", fetch = FetchType.LAZY)
    @OrderBy(value = "createTime desc")
    @Cascade(value = { CascadeType.DELETE })
    private List<ContractPayment> contractPayments;

    @OneToMany(mappedBy = "contract", fetch = FetchType.LAZY)
    @OrderBy(value = "createTime desc")
    @Cascade(value = { CascadeType.DELETE })
    private List<ContractInvoice> contractInvoices;

    @OneToMany(mappedBy = "contract", fetch = FetchType.LAZY)
    @OrderBy(value = "code")
    @Cascade(value = { CascadeType.DELETE })
    private List<ContractItem> contractItems;

    @OneToMany(fetch = FetchType.LAZY)
    // @ElementCollection(fetch=FetchType.LAZY,targetClass=Upload.class)
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumn(name = "ownerId", referencedColumnName = "id")
    private List<ContractAttachment> attachments;

    @Column(columnDefinition = DefineVarchar32)
    @NotBlank
    @Size(max = DefineSize32)
    private String code;// 合同编号

    @Column(columnDefinition = DefineVarchar2048)
    @Size(max = DefineSize2048)
    private String supplier;// 供货商

    @DataType(TapestryEx.DataType_currency)
    private BigDecimal totalPrice = BigDecimalUtil.Int0;// 总价

    @DataType(TapestryEx.DataType_currency)
    private BigDecimal accountPaid = BigDecimalUtil.Int0;// 已付款

    @DataType(TapestryEx.DataType_currency)
    private BigDecimal invoicePaid = BigDecimalUtil.Int0;

    @DataType(TapestryEx.DataType_currency)
    private BigDecimal receivingPrice = BigDecimalUtil.Int0;

    private int numUnreplyPayment;// 付款完成

    private int numUnreplyInvoice;// 发票

    private int numUnreceiving;

    private int numUnpassAndUnexamine;// 验货

    private String status = Status_UnOk;

    private boolean askDelete;

    private boolean askReset;

    @ManyToOne(fetch = FetchType.EAGER)
    @NotFound(action = NotFoundAction.IGNORE)
    private Uzer financial;// 财务接口人

    @ManyToOne(fetch = FetchType.EAGER)
    @NotFound(action = NotFoundAction.IGNORE)
    private Uzer production;// 生产接口人

    @ManyToOne(fetch = FetchType.EAGER)
    @NotFound(action = NotFoundAction.IGNORE)
    private Uzer auditor;//审核人

    @ManyToOne(fetch = FetchType.EAGER)
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumn(name = "createrUsername", referencedColumnName = "username", insertable = false, updatable = false)
    private Uzer creater;// 采购部

    @Column(columnDefinition = "varchar(32) default ''")
    @Size(max = 32)
    @DataType(TapestryEx.DataType_daytime)
    private String createrUsername;

    @Column(columnDefinition = "varchar(32) default ''")
    @NotBlank
    @Size(max = 32)
    private String finacialRealName;

    @Column(columnDefinition = "varchar(32) default ''")
    @NotBlank
    @Size(max = 32)
    private String productionRealName;

    @Column(columnDefinition = "varchar(32) default ''")
    @NotBlank
    @Size(max = 32)
    private String auditorRealName;

    @Column(columnDefinition = "varchar(32) default ''")
    @NotBlank
    @Size(max = 32)
    private String createrRealName;

    @Column(columnDefinition = "varchar(2048) default ''")
    private String fileName;

    @Column(columnDefinition = "varchar(2048) default ''")
    private String remark;

    // logic

    public synchronized String computeStatusCode() {
        if (Status_Cancel.endsWith(status)) {
            return status;
        }
        if (BigDecimalUtil.notEquals(accountPaid, totalPrice)) {
            return Status_UnOk;
        }
        if (BigDecimalUtil.notEquals(invoicePaid, accountPaid)) {
            return Status_UnOk;
        }
        if (numUnreceiving != 0) {
            return Status_UnOk;
        }
        if (numUnpassAndUnexamine != 0) {
            return Status_UnOk;
        }
        if (numUnreplyPayment != 0) {
            return Status_UnOk;
        }
        if (numUnreplyInvoice != 0) {
            return Status_UnOk;
        }
        return Status_Ok;
    }

    public void updateForAddItem(ContractItem item) {
        this.numUnreceiving += 1;
        // this.numUnexamine += 1;
        // this.numUnpass += 1;
        //this.receivingPrice
        this.totalPrice = this.totalPrice.add(item.getTotalPrice());
        this.computeStatusCode();
    }

    public void updateForItem() {
        this.numUnreceiving = 0;
        this.numUnpassAndUnexamine = 0;
        this.totalPrice = BigDecimalUtil.Int0;
        this.receivingPrice = BigDecimalUtil.Int0;
        for (ContractItem item : contractItems) {
            if (!item.isReceivingOk()) {
                this.numUnreceiving += 1;
            }
            if (!item.isPassOk()) {
                this.numUnpassAndUnexamine += 1;
            }
            this.receivingPrice = this.receivingPrice.add(item.getReceivingPrice());
            this.totalPrice = this.totalPrice.add(item.getTotalPrice());
        }
        this.computeStatusCode();
    }

    public void updateForAddPayment(ContractPayment payment) {
        if (payment.getPaymentType() == ContractPayment.Askfor_Payment) {
            this.numUnreplyPayment += 1;
        } else {
            this.numUnreplyPayment -= 1;
            if (payment.isRefund()) {
                this.accountPaid = this.accountPaid.subtract(payment.getPayment());
            } else {
                this.accountPaid = this.accountPaid.add(payment.getPayment());
            }
        }
        this.computeStatusCode();
    }

    public void updateForAddInvoice(ContractInvoice invoice) {
        if (invoice.getInvoiceType() == ContractInvoice.Askfor_Invoice) {
            this.numUnreplyInvoice += 1;
        } else {
            this.numUnreplyInvoice -= 1;
            if (invoice.isHadInvoice()) {
                this.invoicePaid = this.invoicePaid.add(invoice.getPayment());
            }
        }
        this.computeStatusCode();
    }

    // get and set

    public List<ContractInvoice> getContractInvoices() {
        return contractInvoices;
    }

    public void setContractInvoices(List<ContractInvoice> contractInvoices) {
        this.contractInvoices = contractInvoices;
    }

    public List<ContractPayment> getContractPayments() {
        return contractPayments;
    }

    public void setContractPayments(List<ContractPayment> contractPayments) {
        this.contractPayments = contractPayments;
    }

    public List<ContractItem> getContractItems() {
        return contractItems;
    }

    public void setContractItems(List<ContractItem> contractItems) {
        this.contractItems = contractItems;
    }

    public List<ContractAttachment> getAttachments() {
        return attachments;
    }

    public void setAttachments(List<ContractAttachment> attachments) {
        this.attachments = attachments;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getSupplier() {
        return supplier;
    }

    public void setSupplier(String supplier) {
        this.supplier = supplier;
    }

    public BigDecimal getTotalPrice() {
        return totalPrice;
    }

    public void setTotalPrice(BigDecimal totalPrice) {
        this.totalPrice = totalPrice;
    }

    public BigDecimal getReceivingPrice() {
        return receivingPrice;
    }

    public void setReceivingPrice(BigDecimal receivingPrice) {
        this.receivingPrice = receivingPrice;
    }

    public BigDecimal getAccountPaid() {
        return accountPaid;
    }

    public void setAccountPaid(BigDecimal accountPaid) {
        this.accountPaid = accountPaid;
    }

    public BigDecimal getInvoicePaid() {
        return invoicePaid;
    }

    public void setInvoicePaid(BigDecimal invoicePaid) {
        this.invoicePaid = invoicePaid;
    }

    public int getNumUnreplyPayment() {
        return numUnreplyPayment;
    }

    public void setNumUnreplyPayment(int numUnreplyPayment) {
        this.numUnreplyPayment = numUnreplyPayment;
    }

    public int getNumUnreplyInvoice() {
        return numUnreplyInvoice;
    }

    public void setNumUnreplyInvoice(int numUnreplyInvoice) {
        this.numUnreplyInvoice = numUnreplyInvoice;
    }

    public int getNumUnreceiving() {
        return numUnreceiving;
    }

    public void setNumUnreceiving(int numUneeceiving) {
        this.numUnreceiving = numUneeceiving;
    }

    public int getNumUnpassAndUnexamine() {
        return numUnpassAndUnexamine;
    }

    public void setNumUnpassAndUnexamine(int numUnpassAndUnexamine) {
        this.numUnpassAndUnexamine = numUnpassAndUnexamine;
    }

    public boolean isContractOk() {
        return Status_Ok.endsWith(status) || Status_Cancel.endsWith(status);
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public boolean isAskDelete() {
        return askDelete;
    }

    public void setAskDelete(boolean askDelete) {
        this.askDelete = askDelete;
    }

    public boolean isAskReset() {
        return askReset;
    }

    public void setAskReset(boolean askReset) {
        this.askReset = askReset;
    }

    public Uzer getFinancial() {
        return financial;
    }

    public void setFinancial(Uzer financial) {
        this.financial = financial;
        if (financial != null) {
            this.finacialRealName = financial.getRealname();
        } else {
            this.finacialRealName = null;
        }
    }

    public Uzer getProduction() {
        return production;
    }

    public void setProduction(Uzer production) {
        this.production = production;
        if (production != null) {
            this.productionRealName = production.getRealname();
        } else {
            this.productionRealName = null;
        }
    }

    public Uzer getCreater() {
        return creater;
    }

    public void setCreater(Uzer creater) {
        this.creater = creater;
        if (creater != null) {
            this.createrUsername = creater.getUsername();
            this.createrRealName = creater.getRealname();
        } else {
            this.createrUsername = null;
            this.createrRealName = null;
        }
    }

    public Uzer getAuditor() {
        return auditor;
    }

    public void setAuditor(Uzer auditor) {
        this.auditor = auditor;
        if (auditor != null) {
            this.auditorRealName = auditor.getRealname();
        } else {
            this.auditorRealName = null;
        }
    }

    public String getAuditorRealName() {
        return auditorRealName;
    }

    public void setAuditorRealName(String auditorRealName) {
        this.auditorRealName = auditorRealName;
    }

    public String getFinacialRealName() {
        return finacialRealName;
    }

    public void setFinacialRealName(String finacialRealName) {
        this.finacialRealName = finacialRealName;
    }

    public String getProductionRealName() {
        return productionRealName;
    }

    public void setProductionRealName(String productionRealName) {
        this.productionRealName = productionRealName;
    }

    public String getCreaterRealName() {
        return createrRealName;
    }

    public void setCreaterRealName(String createrRealName) {
        this.createrRealName = createrRealName;
    }

    public String getCreaterUsername() {
        return createrUsername;
    }

    public void setCreaterUsername(String createrUsername) {
        this.createrUsername = createrUsername;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public String toString() {
        return this.code;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof Contract)) {
            return false;
        }
        Contract other = (Contract) o;
        return new EqualsBuilder().append(this.code, other.getCode()).isEquals();
    }

    public int hashCode() {
        return new HashCodeBuilder().append(this.code).toHashCode();
    }

}
